﻿using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.Windows.Threading;
using System.IO;
using NS_Client.Data;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Windows.Forms;

namespace NS_Client
{



    public class CommsLogic
    {
        private class NS_Consumer<T>
        {
            Thread _this_T;
            private Queue<T> _queue = new Queue<T>();

            public NS_Consumer(Action ConsumeAction)
            {
                (_this_T = new Thread(new ThreadStart(ConsumeAction.Invoke))).Start();
            }

            public void Abort()
            {
                _this_T.Abort();
            }

            public void Push(T value)
            {
                lock (this)
                {
                    _queue.Enqueue(value);
                    Monitor.Pulse(this);
                }
            }

            public T Pop()
            {
                lock (this)
                {
                    while (_queue.Count == 0)
                        Monitor.Wait(this);

                    return _queue.Dequeue();
                }
            }
        }

        /// <summary>Reference pointer to a SessionModel associated with this instance</summary>
        private static SessionModel _Session;
        private ResponseHandler Response = new ResponseHandler(Dispatcher.CurrentDispatcher);
        private string UploadFilePath;

        private NS_Consumer<string> CommsConsumerT;
        private static NS_Consumer<Action> JobConsumerT;

        /// <summary>Initializes a Logic instance</summary>
        /// <param name="Session">Reference to SessionModel</param>
        public CommsLogic(ref SessionModel Session)
        {
            _Session = Session;
            Response.MessageChanged += new MessageChangedHandler(Reply_MessageChanged);

            CommsConsumerT = new NS_Consumer<string>((Action)delegate { Comms_Consumer(); });
            JobConsumerT = new NS_Consumer<Action>((Action)delegate { Job_Consumer(); });
            Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
        }

        void Application_ApplicationExit(object sender, EventArgs e)
        {
            CommsConsumerT.Abort();
            JobConsumerT.Abort();
        }

        public void SendProtocolMessage(string message)
        {
            CommsConsumerT.Push(message);
        }
        public void CreateContent(string CreateContentDescription_protocolString, string filepath)
        {
            UploadFilePath = filepath;
            CommsConsumerT.Push(CreateContentDescription_protocolString);
        }

        public void DownloadFile(string address, string filename)
        {
            JobConsumerT.Push((Action)delegate { Comms.Download(address, filename); });
        }

        public static void DownloadImage(ContentItem ModifiedItem, string address)
        {
            JobConsumerT.Push((Action)delegate
            {
                try
                {
                    List<ContentItem> ItemsList = _Session.ContentItems;

                    int index = ItemsList.IndexOf(ModifiedItem);
                    ContentItem newItem = ItemsList[index];
                    newItem.ImagePath = System.Drawing.Bitmap.FromStream(new MemoryStream(new WebClient().DownloadData(address)));
                    ItemsList.RemoveAt(index);
                    ItemsList.Insert(index, newItem);
                }
                catch (Exception e) { }
            });
        }

        private void Comms_Consumer()
        {
            while (true)
                try
                {
                    {
                        string MessageToSend = (string)CommsConsumerT.Pop();
                        string response = Comms.HttpPost(MessageToSend);
                        var Parsed_reply = Parser.ParseResponse(response);
                        Response.HandleResponse(Parsed_reply);
                    }
                }
                catch (Exception e) { }
        }

        private void Job_Consumer()
        {
            while (true)
            {
                try
                {
                    JobConsumerT.Pop().Invoke();
                }
                catch (Exception e) { }
            }
        }

        private void Reply_MessageChanged(object sender, object args)
        {
            try
            {
                Dictionary<string, object> ParamKeyVals = (Dictionary<string, object>)args;

                string CommandType = (string)ParamKeyVals[Protocol.Keys.ProtocolCmd];

                #region login reply
                if (CommandType == Protocol.Cmd_Values.LoginSuccess)
                {
                    _Session.SessionID = (string)ParamKeyVals[Protocol.Keys.LoginKey];
                    _Session.LoggedIn = true;

                    return;
                }
                #endregion

                #region Get Content List Reply

                if (CommandType == Protocol.Cmd_Values.StoreSoftwareList)
                {
                    List<Dictionary<string, string>> Table = (List<Dictionary<string, string>>)ParamKeyVals[Protocol.Keys.Software];
                    List<ContentItem> Items = _Session.ContentItems;

                    foreach (Dictionary<string, string> Entry in Table)
                    {
                        Items.Add(new ContentItem((string)Entry[Protocol.Keys.ID], Entry[Protocol.Keys.Name], Entry[Protocol.Keys.Description], Entry[Protocol.Keys.OwnerUsername], int.Parse(Entry[Protocol.Keys.ApprovalStatus]), Entry[Protocol.Keys.SoftwareImagePath]));
                    }

                    _Session.ContentItems = Items;

                    return;
                }
                #endregion

                #region Download content item reply
                if (CommandType == Protocol.Cmd_Values.DownloadSoftware)
                {
                    string Url = (string)ParamKeyVals["NS_SOFTWAREPATH"];
                    string Name = (string)ParamKeyVals["NAME"];
                    DownloadFile(Url, Name);
                    return;
                }
                #endregion

                #region CreateSoftwareDescription reply
                if (CommandType == "SoftwareDescriptionCreation")
                {

                }
                #endregion

                #region Chat Reply
                if (CommandType == Protocol.Cmd_Values.ChatMessages)
                {
                    //ArrayList ChatLog = _Session.ChatLog;

                    //List<Dictionary<string, string>> ChatLogTable = (List<Dictionary<string, string>>)ParamKeyVals[Protocol.Keys.Messages];

                    //foreach (KeyValuePair<string, string> pair in ChatLogTable)
                    //{
                        
                    //    ChatLog.Add(pair.Value);
                    //}

                    
                    //_Session.ChatLog = ChatLog;
                }
                #endregion

                #region FileUploadRequest reply
                if (CommandType == Protocol.Cmd_Values.FileUploadRequest)
                {
                    // the new file name to rename our upload file to
                    string newFileName = (string)ParamKeyVals[Protocol.Keys.FileName];

                    // gets just the old name of the file
                    char[] Filename = UploadFilePath.Split('\\')[UploadFilePath.Split('\\').Length - 1].ToCharArray();

                    // NewFilePath = OldFilePath removed of old name, new file name appended
                    string NewFilePath = UploadFilePath.TrimEnd(Filename) + newFileName;

                    // rename the file via move command
                    File.Move(UploadFilePath, NewFilePath);


                    JobConsumerT.Push((Action)delegate { Comms.FtpUpload(NewFilePath); });
                }
            }
            catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.ToString()); };
                #endregion
        }
    }
}
